package com.quiz.bis.template.pdf;

import com.quiz.bis.domain.vo.PaperPreviewVO;
import com.quiz.bis.domain.vo.PaperQuestionDetailVO;
import com.quiz.bis.domain.vo.QuestionAnswerVo;
import com.quiz.bis.domain.vo.QuestionOptionVo;
import com.quiz.file.domain.model.FileInfo;
import com.quiz.file.service.IFileService;
import lombok.RequiredArgsConstructor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.parser.Tag;
import org.jsoup.select.Elements;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXIcon;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.nio.file.Files;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * 试卷html模版
 * </p>
 * 用于 PDF导出
 *
 * @author ahuan
 */
@Component
@RequiredArgsConstructor
public class PaperHTML {

    private final IFileService fileService;

    @SuppressWarnings("all")
    public String builder(PaperPreviewVO paper, HttpServletRequest request) {
        // 构建HTML内容
        StringBuilder htmlBuilder = new StringBuilder();
        htmlBuilder.append("<!DOCTYPE html>");
        htmlBuilder.append("<html>");
        htmlBuilder.append("<head>");
        htmlBuilder.append("<meta charset=\"UTF-8\"/>");
        htmlBuilder.append("<title>").append(escapeHtml(paper.getTitle())).append("</title>");
        processStyle(htmlBuilder);
        htmlBuilder.append("</head>");
        processBody(htmlBuilder, paper, request);
        htmlBuilder.append("</html>");
        return htmlBuilder.toString();
    }

    // 处理style
    private void processStyle(StringBuilder htmlBuilder) {
        htmlBuilder.append("<style>")
                .append("body { font-family: SimSun; line-height: 1.5; }")
                .append(".header { text-align: center; margin-bottom: 20px; }")
                .append(".paper-title { font-size: 22px; font-weight: bold; margin-bottom: 10px; }")
                .append(".paper-info { margin-bottom: 15px; font-size: 14px; }")
                .append(".paper-info span { margin-right: 15px; }")
                .append(".question-type { font-size: 18px; font-weight: bold; margin: 15px 0 10px 0; border-bottom: 1px solid #eee; padding-bottom: 5px; }")
                .append(".question-item { margin-bottom: 20px; page-break-inside: avoid; }")
                .append(".question-title { font-weight: bold; margin-bottom: 8px; }")
                .append(".question-content { margin-bottom: 10px; }")
                .append(".question-meta { font-size: 12px; color: #666; margin-bottom: 8px; }")
                .append(".question-meta span { margin-right: 10px; }")
                .append(".options { margin-left: 20px; }")
                .append(".option-item { margin-bottom: 5px; }")
                .append(".correct-option { color: #52c41a; font-weight: bold; }")
                .append(".answer-section, .analysis-section { margin-top: 10px; padding: 8px; background-color: #f5f5f5; border-radius: 4px; }")
                .append(".section-title { font-weight: bold; margin-bottom: 5px; }")
                .append(".knowledge-points { font-size: 12px; color: #666; margin-top: 5px; }")
                .append(".knowledge-point { display: inline-block; margin-right: 5px; padding: 2px 5px; background-color: #e6f7ff; border-radius: 3px; }")
                .append(".editor-content-view { ")
                .append("  border: 1px solid #eee; ")
                .append("  border-radius: 3px; ")
                .append("  padding: 10px; ")
                .append("  margin: 15px 0; ")
                .append("  box-shadow: 0 1px 3px rgba(0,0,0,0.1); ")
                .append("}")
                .append(".editor-content-view p, .editor-content-view li { white-space: pre-wrap; margin: 0; padding: 0; }")
                .append(".editor-content-view blockquote { border-left: 8px solid #d0e5f2; padding: 10px; margin: 10px 0; background-color: #f1f1f1; }")
                .append(".editor-content-view code { font-family: monospace; background-color: #eee; padding: 3px; border-radius: 3px; }")
                .append(".editor-content-view pre>code { display: block; padding: 10px; overflow-x: auto; }")
                .append(".editor-content-view table { border-collapse: collapse; width: 100%; margin: 10px 0; border: 1px solid #000; }")
                .append(".editor-content-view td, .editor-content-view th { border: 1px solid #000; padding: 8px; text-align: left; }")
                .append(".editor-content-view th { background-color: #f1f1f1; font-weight: bold; }")
                .append(".editor-content-view tr:nth-child(even) { background-color: #f9f9f9; }")
                .append(".editor-content-view ul, .editor-content-view ol { padding-left: 20px; margin: 5px 0; }")
                .append(".editor-content-view img { max-width: 100%; height: auto; display: block; margin: 5px auto; }")
                .append(".editor-content-view input[type='checkbox'] { margin-right: 5px; }")
                .append(".katex { font-size: 1.1em; }")
                .append(".katex-display { margin: 0.5em 0; overflow-x: auto; overflow-y: hidden; }")
                .append("</style>");
    }

    // 处理body
    private void processBody(StringBuilder htmlBuilder, PaperPreviewVO paper, HttpServletRequest request) {
        htmlBuilder.append("<body>");

        // 试卷头部信息
        htmlBuilder.append("<div class='header'>");
        htmlBuilder.append("<div class='paper-title'>").append(escapeHtml(paper.getTitle())).append("</div>");
        htmlBuilder.append("<div class='paper-info'>");
        htmlBuilder.append("<span>试卷编号: ").append(escapeHtml(paper.getCode())).append("</span>");
        htmlBuilder.append("<span>总分: ").append(paper.getTotalScore()).append("分</span>");
        htmlBuilder.append("<span>及格分: ").append(paper.getPassScore()).append("分</span>");
        if (paper.getTimeLimit() != null && paper.getTimeLimit() > 0) {
            htmlBuilder.append("<span>考试时长: ").append(paper.getTimeLimit()).append("分钟</span>");
        }
        htmlBuilder.append("</div>");
        htmlBuilder.append("</div>");

        // 试卷备注
        if (paper.getRemark() != null && !paper.getRemark().isEmpty()) {
            htmlBuilder.append("<div class='remark'>")
                    .append(processHtmlContent(paper.getRemark(), request))
                    .append("</div>");
        }

        // 按题型分组显示题目
        if (paper.getQuestionsByType() != null) {
            for (Map.Entry<String, List<PaperQuestionDetailVO>> entry : paper.getQuestionsByType().entrySet()) {
                String typeName = entry.getKey();
                List<PaperQuestionDetailVO> questions = entry.getValue();

                htmlBuilder.append("<h2 class='question-type'>").append(typeName).append("</h2>");

                for (PaperQuestionDetailVO question : questions) {
                    htmlBuilder.append("<div class='question-item'>");

                    // 题目标题和分数
                    htmlBuilder.append("<div class='question-title'>")
                            .append(question.getSort()).append(". ")
                            .append(escapeHtml(question.getTitle()))
                            .append(" (").append(question.getScore()).append("分)")
                            .append("</div>");

                    // 题目内容
                    htmlBuilder.append("<div class='question-content'>")
                            .append(processHtmlContent(question.getContent(), request))
                            .append("</div>");

                    // 知识点
                    if (paper.getPreviewOptions().isShowKnowledgePoints()
                            && question.getKnowledgePoints() != null
                            && !question.getKnowledgePoints().isEmpty()) {
                        htmlBuilder.append("<div class='knowledge-points'>知识点: ");
                        for (String point : question.getKnowledgePoints()) {
                            htmlBuilder.append("<span class='knowledge-point'>").append(escapeHtml(point)).append("</span>");
                        }
                        htmlBuilder.append("</div>");
                    }

                    // 选项
                    if (question.getOptions() != null && !question.getOptions().isEmpty()) {
                        htmlBuilder.append("<div class='options'>")
                                .append(processPaperOptions(question.getOptions(), paper.getPreviewOptions().isShowOptionAnswers()))
                                .append("</div>");
                    }

                    // 答案
                    if (paper.getPreviewOptions().isShowAnswers()
                            && question.getAnswers() != null
                            && !question.getAnswers().isEmpty()) {
                        htmlBuilder.append("<div class='answer-section'>")
                                .append("<div class='section-title'>答案</div>")
                                .append(processPaperAnswers(question.getAnswers()))
                                .append("</div>");
                    }

                    // 解析
                    if (paper.getPreviewOptions().isShowAnalysis()
                            && question.getAnalysis() != null
                            && !question.getAnalysis().isEmpty()) {
                        htmlBuilder.append("<div class='analysis-section'>")
                                .append("<div class='section-title'>解析</div>")
                                .append(processHtmlContent(question.getAnalysis(), request))
                                .append("</div>");
                    }

                    htmlBuilder.append("</div>"); // 结束question-item
                }
            }
        }

        htmlBuilder.append("</body>");
    }

    // 处理选项列表
    private String processPaperOptions(List<QuestionOptionVo> options, boolean showCorrect) {
        if (options == null || options.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (QuestionOptionVo option : options) {
            sb.append("<div class='option-item");
            if (showCorrect && option.getIsCorrect() != null && option.getIsCorrect() == 1) {
                sb.append(" correct-option");
            }
            sb.append("'>")
                    .append(option.getOptionCode()).append(". ")
                    .append(processHtmlContent(option.getContent(), null))
                    .append("</div>");
        }
        return sb.toString();
    }

    // 处理答案列表
    private String processPaperAnswers(List<QuestionAnswerVo> answers) {
        if (answers == null || answers.isEmpty()) return "";
        StringBuilder sb = new StringBuilder();
        for (QuestionAnswerVo answer : answers) {
            sb.append(processHtmlContent(answer.getContent(), null));
        }
        return sb.toString();
    }

    // 处理HTML内容
    private String processHtmlContent(String html, HttpServletRequest request) {
        if (html == null || html.isEmpty()) return "";

        Document doc = Jsoup.parseBodyFragment(html);
        Element body = doc.body();

        // 深度遍历处理所有元素
        processElementsRecursively(body, request);

        return body.html();
    }

    // 递归处理所有元素
    private void processElementsRecursively(Element element, HttpServletRequest request) {
        // 先处理子元素
        Elements children = element.children();
        for (Element child : children) {
            processElementsRecursively(child, request);
        }

        // 处理当前元素
        if (element.tagName().equalsIgnoreCase("span")
                && "formula".equalsIgnoreCase(element.attr("data-w-e-type"))) {
            processFormulaElement(element);
        } else if (element.tagName().equalsIgnoreCase("img")) {
            processImageElement(element, request);
        }

        // 处理表格
        if (element.tagName().equalsIgnoreCase("table")) {
            element.addClass("editor-content-table");
            // 确保表格有边框
            if (!element.hasAttr("border")) {
                element.attr("border", "1");
            }
            if (!element.hasAttr("cellspacing")) {
                element.attr("cellspacing", "0");
            }
            if (!element.hasAttr("cellpadding")) {
                element.attr("cellpadding", "5");
            }
        }
    }

    // 处理数学公式元素
    private void processFormulaElement(Element element) {
        String latex = element.attr("data-value");
        try {
            byte[] imageData = renderLatexToImage(latex);
            String base64 = Base64.getEncoder().encodeToString(imageData);
            Element img = new Element(Tag.valueOf("img"), "")
                    .attr("src", "data:image/png;base64," + base64)
                    .attr("style", "vertical-align: middle;")
                    .attr("alt", "公式: " + latex);
            element.replaceWith(img);
        } catch (Exception e) {
            element.replaceWith(new TextNode("[公式渲染错误: " + latex + "]"));
        }
    }

    // 处理图片元素
    private void processImageElement(Element img, HttpServletRequest request) {
        String src = img.attr("src");
        if (src.startsWith("data:")) {
            // 已经是base64数据，不需要处理
            return;
        }

        // 从URL中提取文件ID
        String fileId = extractFileIdFromUrl(src);
        if (fileId != null) {
            try {
                // 获取文件并转换为base64
                FileInfo fileInfo = fileService.getFileById(Long.parseLong(fileId));
                File file = new File(fileInfo.getFilePath());
                byte[] fileContent = Files.readAllBytes(file.toPath());
                String base64 = Base64.getEncoder().encodeToString(fileContent);
                String mimeType = Files.probeContentType(file.toPath());

                img.attr("src", "data:" + mimeType + ";base64," + base64)
                        .attr("style", "max-width: 100%; height: auto; display: block; margin: 5px auto;");
            } catch (Exception e) {
                img.attr("src", "")
                        .attr("alt", "[图片加载失败: " + fileId + "]");
            }
        }
    }

    // 从URL中提取文件ID
    private String extractFileIdFromUrl(String url) {
        // 匹配类似1915099229114634242这样的数字ID
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("/(\\d+)(\\?|$)");
        java.util.regex.Matcher matcher = pattern.matcher(url);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    // 渲染LaTeX为图片
    private byte[] renderLatexToImage(String latex) throws Exception {
        TeXFormula formula = new TeXFormula(latex);
        TeXIcon icon = formula.createTeXIcon(TeXConstants.STYLE_TEXT, 16);
        icon.setInsets(new Insets(2, 2, 2, 2));

        BufferedImage image = new BufferedImage(
                icon.getIconWidth(),
                icon.getIconHeight(),
                BufferedImage.TYPE_INT_ARGB
        );
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        icon.paintIcon(null, g2, 0, 0);
        g2.dispose();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", baos);
        return baos.toByteArray();
    }

    // HTML转义
    private String escapeHtml(String text) {
        if (text == null) return "";
        return text.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#39;");
    }
}